package Games;

import java.awt.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;

/**
 * 贪吃蛇游戏逻辑
 */
public class Snake {

    int Rows = 0, Columns = 0;
    Direction direction = Direction.Right;
    public List<Point> Nodes = new ArrayList<>();
    public Point Food = null;

    /**
     * 构造方法
     * @param width 地图宽度
     * @param height 地图高度
     */
    public Snake(int width, int height){
        //地图边界
        this.Rows = height;
        this.Columns = width;
        //重置
        this.Reset();
    }

    /**
     * 重置贪吃蛇
     */
    public void Reset()
    {
        //默认方向
        direction = Direction.Right;
        //初始化蛇身
        Nodes.clear();
        for(int i=0; i<3; i++){
            Point p = new Point(0, i);
            Nodes.add(p);
        }
        //生成食物
        Food = this.GenerateFood();
    }

    /**
     * 蛇身移动
     * @throws Exception 游戏结束
     */
    public void Move() throws Exception {
        //移动处理
        Point head = Nodes.get(Nodes.size() - 1);
        int x = head.x, y = head.y;
        switch (direction){
            case Right: y++; break;
            case Left: y--; break;
            case Down: x++; break;
            case Up: x--; break;
            default: break;
        }
        //节点处理
        Point next = new Point(x, y);
        if(next != null){
            Boolean isFood = Food != null && x == Food.x && y == Food.y;
            //食物处理
            if(!isFood) {
                Nodes.remove(Nodes.get(0)); //去除第0个，即蛇尾
            } else {
                Food = this.GenerateFood();
            }
            //游戏结束判断
            if(next.x < 0 || next.x > Rows-1 || next.y < 0 || next.y > Columns-1){
                throw new Exception("游戏结束：撞到边界");
            }
            if(this.IsBody(next.x, next.y)){
                throw new Exception("游戏结束：撞到自身");
            }

//            AutoTurn();
//            AutoPass();

            //移动/吃食物
            Nodes.add(next);
        }
    }

    /**
     * 设置移动方向
     * @param d 方向
     */
    public void SetDirection(Direction d){
        //是否逆向
        Boolean isReverse = false;
        switch (direction){
            case Right: isReverse = Direction.Left == d; break;
            case Left: isReverse = Direction.Right == d; break;
            case Down: isReverse = Direction.Up == d; break;
            case Up: isReverse = Direction.Down == d; break;
            default: break;
        }
        //逆向处理
        if(isReverse){
            Point temp = null;
            int len = Nodes.size();
            for(int i=0; i<len/2; i++){
                int x = len-1-i;
                temp = Nodes.get(i);
                Nodes.set(i, this.Nodes.get(x));
                Nodes.set(x, temp);
            }
        }
        this.direction = d;
    }

    /**
     * 生成食物
     * @return Point
     */
    private Point GenerateFood(){
        int x=0, y=0;
        Random rand = new Random();
        while (true){
            x = rand.nextInt(this.Rows);
            y = rand.nextInt(this.Columns);
            if(this.IsBody(x, y)){
                continue;
            }
            break;
        }

        return new Point(x, y);
    }

    /**
     * 是否蛇身节点
     * @param x 横坐标
     * @param y 纵坐标
     * @return bool
     */
    private Boolean IsBody(int x, int y){
        for(Point p: this.Nodes){
            if(x == p.x && y == p.y){
                System.out.println("x: " + x + " y: " + y);
                return true;
            }
        }
        return false;
    }

    /**
     * 自动转弯
     */
    private void AutoTurn(){
        Point head = this.Nodes.get(this.Nodes.size() - 1);
        Boolean right_edge = head.y >= Columns-1;
        Boolean down_edge = head.x >= Rows-1;
        Boolean left_edge = head.y <= 0;
        Boolean up_edge = head.x <= 0;
        if((right_edge || left_edge) && (direction == Direction.Right || direction == Direction.Left)) {
            this.SetDirection(down_edge ? Direction.Up : Direction.Down);
        }
        else if((down_edge || up_edge) && (direction == Direction.Down || direction == Direction.Up)){
            this.SetDirection(right_edge ? Direction.Left : Direction.Right);
        }
    }

    /**
     * 自动穿墙
     */
    private void AutoPass(){
        Point head = this.Nodes.get(this.Nodes.size() - 1);
        Boolean right_edge = direction == Direction.Right && head.y > Columns-1;
        Boolean down_edge = direction == Direction.Down && head.x > Rows-1;
        Boolean left_edge = direction == Direction.Left && head.y < 0;
        Boolean up_edge = direction == Direction.Up && head.x < 0;
        if(right_edge){
            head.y = 0;
        }
        else if(down_edge){
            head.x = 0;
        }
        else if(left_edge){
            head.y = Columns-1;
        }
        else if(up_edge){
            head.x = Rows-1;
        }
    }
}
